use crate::db::FUDB;
use crate::model::indicators;
use crate::model::indicators::sar;
use crate::model::indicators::IndicatorResultWrap;
///
use crate::model::kline::Kline;
use crate::model::FudaRecord;
use anyhow::anyhow;
use anyhow::ensure;
use anyhow::Result;
use surrealdb::opt::PatchOp;
use surrealdb::sql::Id;
use surrealdb::sql::Thing;
use yata::core::Candle;
use yata::core::IndicatorConfig;
use yata::core::IndicatorInstance;
use yata::indicators::ParabolicSARInstance;

#[derive(Debug)]
pub struct Sar {
    sar_instance: ParabolicSARInstance,
}

impl Sar {
    pub fn new(conf: &sar::SARConfig, init_kline: &Kline) -> Result<Self> {
        let sar = yata::indicators::ParabolicSAR {
            af_step: conf.af_step,
            af_max: conf.af_max,
        };
        let candle: Candle = init_kline.into();
        let sar_instance: ParabolicSARInstance = sar.init(&candle)?;
        Ok(Sar { sar_instance })
    }

    pub fn next(&mut self, kline: &Kline) -> sar::SAR {
        Self::compute(&mut self.sar_instance, kline)
    }

    pub fn repeat(&mut self, kline: &Kline) -> sar::SAR {
        let mut sar_instance = self.sar_instance.clone();
        Self::compute(&mut sar_instance, kline)
    }

    fn compute(sar_instance: &mut ParabolicSARInstance, kline: &Kline) -> sar::SAR {
        let candle: Candle = kline.into();

        let idr: yata::core::IndicatorResult = sar_instance.next(&candle);

        let idrw: IndicatorResultWrap = IndicatorResultWrap::from(&idr);

        let value = sar::SAR {
            signal0: idrw.s0,
            sar: idrw.v0,
            trend: idrw.v1,
        };

        return value;
    }
}

/// 更新指定K线数据的SAR,现在只能做全量计算
///
/// @param klines: K线数据
///
/// config: Sar 设置
///
/// return 更新的记录数
///
pub async fn update_sar(
    klines: &Vec<Kline>,
    config: Option<indicators::sar::SARConfig>
) -> Result<u32> {
    ensure!(klines.len() > 0, "klines is empty");
    let mut updates = 0u32;
    if let Some(fstk) = klines.first() {
        let sar = match config {
            Some(conf) =>
                yata::indicators::ParabolicSAR {
                    af_step: conf.af_step,
                    af_max: conf.af_max,
                },
            None => yata::indicators::ParabolicSAR::default(),
        };

        let mut sar: yata::indicators::ParabolicSARInstance = sar.init(
            &(fstk.open, fstk.high, fstk.low, fstk.close, fstk.volume as f64)
        )?;

        for (i, kline) in klines.iter().enumerate() {
            if let Some(Thing { id: Id::String(kid_str), .. }) = &kline.id {
                let idr: yata::core::IndicatorResult = sar.next(
                    &(kline.open, kline.high, kline.low, kline.close, kline.volume as f64)
                );

                println!("idr[{i}] close={} ==> {:?}", kline.close, idr);

                let idrw: IndicatorResultWrap = IndicatorResultWrap::from(&idr);

                let sar = indicators::sar::SAR {
                    signal0: idrw.s0,
                    sar: idrw.v0,
                    trend: idrw.v1,
                };

                let updated: Option<FudaRecord> = FUDB.update(("kline", kid_str))
                    .patch(PatchOp::replace("/sar", sar)).await
                    .map_err(|err| anyhow!(err))?;

                if let Some(_) = updated {
                    updates += 1;
                }
            }
        }
    }

    Ok(updates)
}

// [00], close:158.07=>sar:Some(SAR { idrw: IndicatorResultWrap { s0: None, v0: 0.09812550159682587, s1: None, v1: 0.519554529034741, s2: None, v2: 0.0, s3: None, v3: 0.0, slen: 2, vlen: 2 }, bar: 0.09812550159682587 })
// [01], close:157.97=>sar:Some(SAR { idrw: IndicatorResultWrap { s0: None, v0: 0.1445212466661019, s1: None, v1: 0.6249117858942198, s2: None, v2: 0.0, s3: None, v3: 0.0, slen: 2, vlen: 2 }, bar: 0.1445212466661019 })
// [02], close:157.13=>sar:Some(SAR { idrw: IndicatorResultWrap { s0: None, v0: 0.21181877951207184, s1: None, v1: 0.7450094207012493, s2: None, v2: 0.0, s3: None, v3: 0.0, slen: 2, vlen: 2 }, bar: 0.21181877951207184 })
// [03], close:158.71=>sar:Some(SAR { idrw: IndicatorResultWrap { s0: None, v0: 0.379855721006237, s1: None, v1: 0.8783070809985437, s2: None, v2: 0.0, s3: None, v3: 0.0, slen: 2, vlen: 2 }, bar: 0.379855721006237 })

#[cfg(test)]
mod test {
    use crate::db;
    use crate::model::indicators;
    use crate::model::kline::Klt;
    use crate::model::kline::KLINE_COMMON_FIELDS;

    #[tokio::test]
    async fn test_update_sar() {
        let _ = db::init().await.unwrap();

        let _config = indicators::sar::SARConfig {
            ..Default::default()
        };

        let klt_vec = vec![
            Klt::M005,
            Klt::M015,
            Klt::M030,
            Klt::M060,
            Klt::DAY,
            Klt::WEEK,
            Klt::MONTH
        ];
        for klt in &klt_vec {
            let klines = db::kline
                ::select("SZ.KZZ.128136", None, Some(klt), Some("klts ASC"), 0, 10000).await
                .unwrap();
            let result = db::indicators::sar::update_sar(&klines, None).await;
            println!("{:?}", result);
            assert_eq!(result.is_ok(), true);
        }

        let result = db::kline::select(
            "SZ.KZZ.128136",
            None,
            Some(&Klt::M005),
            Some("klts ASC"),
            0,
            100
        ).await;
        if let Ok(klines) = &result {
            for (index, kline) in klines.iter().enumerate() {
                if index > 30 {
                    break;
                }
                // println!(
                //     "[{:02}], close:{:.2}=>sar:{:?}",
                //     index, kline.close, kline.sar,
                // );
            }
        }
    }
}
// [00], close:158.07=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.3083, signal_v: 0.3228 })
// [01], close:157.97=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.3272, signal_v: 0.3482 })
// [02], close:157.13=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.3328, signal_v: 0.3769 })
// [03], close:158.71=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.3846, signal_v: 0.4222 })
// [04], close:156.67=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.4132, signal_v: 0.4654 })
// [05], close:159.00=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.4688, signal_v: 0.5145 })
// [06], close:158.79=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.5143, signal_v: 0.5618 })
// [07], close:158.32=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.5603, signal_v: 0.612 })
// [08], close:159.26=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.6108, signal_v: 0.6604 })
// [09], close:159.67=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.6648, signal_v: 0.6962 })
// [10], close:159.80=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.7057, signal_v: 0.7229 })
// [11], close:159.32=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.7179, signal_v: 0.7423 })
// [12], close:160.20=>sar:Some(SAR { signal0: None, signal1: None, signal2: None, main_v: 0.745, signal_v: 0.7648 })
